/*
 *has all the methods that are made for cells like getting its row,getting its
 * column,getting its block e.t.c
 * 
 */
package sudokusolver;

import java.util.HashSet;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
public class Cell {
    Set<Integer> markup = new HashSet<Integer>();  
    int finalVal;
    int rowValue;
    int columnValue;
    Grid parent;
    private static List foronst=new ArrayList();
    private static List st=new ArrayList();
    public Cell (Grid grid) {
        markup.add(1);
        markup.add(2);
        markup.add(3);
        markup.add(4);
        markup.add(5);
        markup.add(6);
        markup.add(7);
        markup.add(8);
        markup.add(9);
        finalVal=0;
        rowValue=0;
        columnValue=0;
        parent=grid;
    }
    public Cell (Grid grid,int row,int col) {
        markup.add(1);
        markup.add(2);
        markup.add(3);
        markup.add(4);
        markup.add(5);
        markup.add(6);
        markup.add(7);
        markup.add(8);
        markup.add(9);
        finalVal=0;
        rowValue=row;
        columnValue=col;
        parent=grid;
    }
    public Cell(Grid grid,int finVal,int row,int col) {
        markup.add(finVal);
        finalVal=finVal;
        rowValue=row;
        columnValue=col;
        parent=grid;
    }
    @Override
    public String toString() {
        return  " " + rowValue + "," + columnValue;
    }
    public void initializeFinalValue() {
        if(markup.size()==1) {
            Object[] ar=markup.toArray();
            finalVal=(Integer)(ar[0]);
        }
    }
    public void initializeFinalValue(int a) {
        finalVal=a;
        markup.clear();
        markup.add(a);
    }
    public Cell[] getRow() {
        return parent.grid[this.rowValue];
    }
    public Cell[] getCol() {
        int j=columnValue;
        Cell[] i=new Cell[Grid.NO_OF_ROWS]; 
        for (int k=0;k<i.length;k++) {
            i[k]=parent.grid[k][j];
        }
        return i;
    }    
    public static boolean find(Cell[] ce,int targ) {
        for(Cell x: ce) {
            if(x.finalVal==targ) return true;
        }
        return false;
    }
    public Cell[] getBlockSaurabh() {
        final int BOXLENGTH = 3;
        Cell[] boxCells = new Cell[Grid.NO_OF_COLUMNS];
        int topLeftRow = rowValue - rowValue % BOXLENGTH; 
        int topLeftColumn = columnValue - columnValue % BOXLENGTH; 
        for(int i=0; i<BOXLENGTH; i++) {
            for(int j=0; j<BOXLENGTH; j++) {             
                boxCells[i*BOXLENGTH + j] = 
                        parent.grid[topLeftRow+j][topLeftColumn+i];
                //computation done.
            }
        }
        return boxCells;
    }
    public void updateMarkup() {
        Cell[] row=getRow();
        Cell[] col=getCol();
        Cell[] block=getBlockSaurabh();
        //searching for naked doubles/triples e.t.c->eliminating candidates from
        //other squares though.     
        if(markup.isEmpty())
        for (int v=0;v<row.length;v++) {
            if (row[v].markup.equals(markup) && row[v]!=this && 
                    markup.size()==2) {
                //if some square in this cell's row has the same markup as this
                //cell
                Object[] ar=markup.toArray();
                for (int w=0;w<row.length;w++) {
                    for (int x=0;x<ar.length;x++) {
                        if(w!=v && row[w]!=this &&
                        row[w].markup.contains(ar[x])) {
                        row[w].markup.remove(ar[x]); //remove
                            //this markup from the other cells.
                        }                        
                    }
                }
            }
        }
        for (int y=0;y<col.length;y++) {
            if (col[y].markup.equals(markup) && col[y]!=this && 
                    markup.size()==2) {
                //if some square in this cell's column has the same markup as
                //this cell
                Object[] ar=markup.toArray();
                for (int z=0;z<col.length;z++) {
                    for (int a=0;a<ar.length;a++) {
                        if(z!=y && col[z]!=this &&
                        col[z].markup.contains(ar[a])) {
                            col[z].markup.remove(ar[a]);
                            //remove this markup from the other cells.
                        }
                    }
                }
            }
        }
        for (int b=0;b<block.length;b++) {
            if(block[b].markup.equals(markup) && block[b]!=this && 
                    markup.size()==2) {
                //if some other cell in this cell's block has the same
                //markup as this cell.
                Object[] ar=markup.toArray();
                for (int c = 0; c <block.length; c++) {
                    for (int d = 0; d < ar.length; d++) {
                        if(c!=b && block[c]!=this &&
                                block[c].markup.contains((Integer)(ar[d]))) {
                                block[c].markup.remove((Integer)(ar[d]));
                        }//if this cell has any elements in that markup,
                        //remove it.
                    }
                }
            }
        }
        //to find naked singles in a row or column or block.  
        int a=checkForHiddenSingles(row);
        if(a!=-1) {
            Object[] ra=Cell.foronst.toArray();
            Set tes=(HashSet)(ra[0]);
            Cell x=findMarkup(tes,row);
            x.initializeFinalValue(a);
            x.removeMarkupsFromAllOfThisCellsBuddies();
        }
        int nex=checkForHiddenSingles(col);
        if(nex!=-1) {
            Object[] ra=Cell.foronst.toArray();
            Set tes=(HashSet)(ra[0]);
            Cell x=findMarkup(tes,col);
            x.initializeFinalValue(nex);
            x.removeMarkupsFromAllOfThisCellsBuddies();
        }
        int nex2=checkForHiddenSingles(block);
        if(nex2!=-1) {
            Object[] ra=Cell.foronst.toArray();
            Set tes=(HashSet)(ra[0]);
            Cell x=findMarkup(tes,block);
            x.initializeFinalValue(nex2);
            x.removeMarkupsFromAllOfThisCellsBuddies();
        }
    }
    public static List markupSetForAllValues(Cell[] ce) {
        List list=new ArrayList();
        for(Cell x:ce) {
                list.add(x.markup);
        }
        return list;
    }
    public static Cell find(Cell[] ce,Cell x) {
        for(Cell y:ce) {
            if(y.equals(x)) {
                return y;
            }
        }
        return null;
    }
    public static List markupSetThatContainsThisElement(List s,int a) {
        Object[] ar=s.toArray();
        List tr=new ArrayList<Set>();
        for(Object obj:ar) {
            Set se=(HashSet)(obj);
            if(se.contains(a)) {
                tr.add(se);
            }
        }
        return tr;
    }
    public static int checkForHiddenSingles(Cell[] ce) {
        Cell.st=markupSetForAllValues(ce);
        for (int e=1;e<=9;e++) {
            List onst=markupSetThatContainsThisElement(Cell.st,e);
            if(onst.size()==1) {
                Cell.foronst.clear();
                Object[] ar=onst.toArray();
                Cell.foronst.add(ar[0]);
                return e; 
            }
        }
        return -1;
    }
    public static Cell findMarkup(Set s,Cell[] ce) {
        for(Cell x:ce){
            if(x.markup.equals(s)) {
                return x;
            }
        }
        return null;
    }
    public Set findAllMarkupsLikeThisOne() {
        Set se=new HashSet();
        Grid grid=parent;
        for (int ty = 0;ty< Grid.NO_OF_ROWS;ty++) {
            for (int tz = 0;tz< Grid.NO_OF_COLUMNS;tz++) {
                if(grid.grid[ty][tz].markup==markup&& !(ty==rowValue&&tz==columnValue)) {
                    se.add(grid.grid[ty][tz]);
                }
            }
        }
        return se;
    }    
    public String getMarkupString()
    {
        StringBuilder s= new StringBuilder("{         }");
        for (int i = 1; i <= Grid.NO_OF_COLUMNS; i++) {
            if(markup.contains(i)) {
                s.setCharAt(i, (i+"").charAt(0));
            }
        }
        return s.toString();
    }
    public void removeMarkupsFromAllOfThisCellsBuddies() {
        Cell[] ar=getRow();
        for(Cell x:ar) {
            if(x!=this && x.markup.contains(this.finalVal)) {
                x.markup.remove(this.finalVal);
            }
        }
        Cell[] ra=getCol();
        for(Cell x:ra) {
            if(x!=this && x.markup.contains(this.finalVal)) {
                x.markup.remove(this.finalVal);
            }
        }
        Cell[] ra1=getBlockSaurabh();
        for(Cell x:ra1) {
            if(x!=this && x.markup.contains(this.finalVal)) {
                x.markup.remove(this.finalVal);
            }
        }
    }
}